package com.glodon.paas.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.glodon.paas.exception.PaasServerExceptionFactory;

public class SimpleBeanConverter {
	
	public static <T,V> T converte(V resource, Class<T> destenation){
		return converteBean(resource, destenation);
	}
	
	public static <T,V> List<T> converte(List<V> resource, Class<T> destenation){
		return converteList(resource, destenation);
	}
	
	private static <T,V> List<T> converteList(List<V> beans, Class<T> dc){
		if(beans == null){
			return null;
		}
		else if(dc == null){
			throw PaasServerExceptionFactory.systemException("convert data fail, destination bean type is null", null);
		}
		else{
			List<V> resos=beans;
			List<T> descs = new ArrayList<T>();
			if(resos.size() > 0){
				Class<?> rc = resos.get(0).getClass();
				T desc;
				Method getterMethod;
				Method setterMethod;
				Set<Field> fields = new HashSet<Field>();
				getFields(dc, fields);
				for(Object reso : resos){
					try {
						desc = dc.newInstance();
					} catch (Exception e1) {
						throw PaasServerExceptionFactory.systemException("convert data fail, can not instance destination bean", e1);
					}
					for (Field f : fields) {
						String fieldName = f.getName();
						Class<?> type = f.getType();
						StringBuffer get = new StringBuffer();
						StringBuffer set = new StringBuffer("set");
						if(type.toString().equals("boolean")){
							get.append("is");
						}
						else{
							get.append("get");
						}
						getterMethod = getGetterMethod(get.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)).toString(), rc);
						setterMethod = getSetterMethod(set.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)).toString(), type, dc); 
						if(getterMethod != null && setterMethod !=null){
							try {
								Object value = getterMethod.invoke(reso);
								if (value != null) {
									setterMethod.invoke(desc, value);
								}
							} catch (Exception e) {
							}
						}
					}
					descs.add(desc);
				}
			}
			return descs;
		}
	}
	
	private static <T,V> T converteBean(V reso, Class<T> dc){
		if(reso == null){
			return null;
		}
		else if(dc == null){
			throw PaasServerExceptionFactory.systemException("convert data fail, destination bean type is null", null);
		}
		else{
			T desc;
			try {
				desc = dc.newInstance();
			} catch (Exception e1) {
				throw PaasServerExceptionFactory.systemException("convert data fail, can not instance destination bean", e1);
			}
			Class<?> rc = reso.getClass();
			Set<Field> fields = new HashSet<Field>();
			getFields(dc, fields);
			for (Field f : fields) {
				String fieldName = f.getName();
				Class<?> type = f.getType();
				Method getterMethod;
				Method setterMethod;
				StringBuffer get = new StringBuffer();
				StringBuffer set = new StringBuffer("set");
				if(type.toString().equals("boolean")){
					get.append("is");
				}
				else{
					get.append("get");
				}
				getterMethod = getGetterMethod(get.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)).toString(), rc);
				setterMethod = getSetterMethod(set.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)).toString(), type, dc); 
				if(getterMethod != null && setterMethod !=null){
					try {
						Object value = getterMethod.invoke(reso);
						if (value != null) {
							setterMethod.invoke(desc, value);
						}
					} catch (Exception e) {
					}
					
				}
			}
			return desc;
		}
	}
	
	  private static Method getGetterMethod(String methodName, Class<?> c)
	  {
		Method method = null;
		Class<?> ic = c;
	    do{
	    	try {
				method = ic.getDeclaredMethod(methodName);
			} catch (NoSuchMethodException e) {
				ic = ic.getSuperclass();
			}
	    }
	    while(method==null && ic.getSuperclass() != null);
	    
	    return method;
	  }
	  
	  private static Method getSetterMethod(String methodName, Class<?> type, Class<?> c)
	  {
		Method method = null;
		Class<?> ic = c;
	    do{
	    	try {
				method = ic.getDeclaredMethod(methodName, type);
			} catch (NoSuchMethodException e) {
				ic = ic.getSuperclass();
			}
	    }
	    while(method==null && ic.getSuperclass() != null);
	    
	    return method;
	  }
	  
	  private  static <T> void getFields(Class<T> dc, Set<Field> fields){
		  Class<?> sup = dc.getSuperclass();
		  if(sup != null && !sup.getName().equals("java.lang.Object")){
			  getFields(sup, fields);
		  }
		  fields.addAll(Arrays.asList(dc.getDeclaredFields()));
	  }
}
